package com.googlecode.jascii;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.apache.commons.io.FileUtils;

import com.googlecode.jascii.util.ShellEngineFactory;

/**
 * @author Kim Lee
 * 
 */

 
public class PageResult {
	protected int defaultTrNum = 42;//預設一頁42行
	protected List trArray = new ArrayList();
	protected List pageIndex = new ArrayList();
	protected List headerArray = new ArrayList();
	protected List footerArray = new ArrayList();
	protected int maxwidth = 0;
	protected  Invocable invocableEngine = null;
	protected StringBuffer shellScript = new StringBuffer(" var PAGENUM =1; ")
	                                              .append(" function nextPageNum(formatS) {  ")
	                                              .append("        var returnStr =  java.lang.String.format(formatS, [ new java.lang.Integer(PAGENUM)] ); PAGENUM++; return returnStr;  ")
	                                              .append(" } ")
	                                              .append(" function getPageNum(formatS) { ")
	                                              .append("        return java.lang.String.format(formatS, [ new java.lang.Integer(PAGENUM)] );  ")
	                                              .append(" } ")
												  .append(" function setPageNum(pageN) { ")
												  .append("        PAGENUM = pageN;  ")
												  .append(" } ");
	
	/**
	 *  
	 */
	public PageResult() {
	}

	public PageResult(int defaultTrNum) {
		this.defaultTrNum = defaultTrNum;
	}
	
	


	/**
	 * 
	 * @param defaultTrNum
	 * @param trArray
	 */
	public PageResult(int defaultTrNum, List trArray,List headerArray,List footerArray) {
		this.defaultTrNum = defaultTrNum;
		this.trArray = trArray;
		this.headerArray = headerArray;
		this.footerArray = footerArray;
	}

	/**
	 * @return 傳回 defaultTrNum。
	 */
	public int getDefaultTrNum() {
		return defaultTrNum - headerArray.size() - footerArray.size();
	}

	/**
	 * @param defaultTrNum
	 *            要設定的 defaultTrNum。
	 */
	public void setDefaultTrNum(int defaultTrNum) {
		reCalPage();
		this.defaultTrNum = defaultTrNum;
	}
	public void renewShellEngine()
	{
		ShellEngineFactory.getInstance().renewShellEngine();
	}
	private Invocable generateInvocableEngine()
	{
		if(invocableEngine!=null)return invocableEngine; 
		//由於過多的Script Engine 會造成錯誤
/*
	        ScriptEngineManager manager = new ScriptEngineManager();
	        ScriptEngine engine = manager.getEngineByExtension("js");
	        try {
				engine.eval(shellScript.toString());
				 //
	            // Convert / cast the engine into invocable engine.
	            //
	             invocableEngine = (Invocable) engine;
			} catch (ScriptException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
  */  
		invocableEngine = ShellEngineFactory.getInstance().getInvocable(shellScript);
		return	invocableEngine;
		
	}
	public void invokingFunction(String function,Object... shellargs) {
		try {
			generateInvocableEngine().invokeFunction(function, shellargs);
		} catch (ScriptException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public PageResult appendShellScript(String shell)
	{
		shellScript.append(shell);
		return this;
	}
	
	public PageResult append(TrResult trResult) {
		if(trResult.getTrType() == TrResult.TD_SCRIPT_TYPE)
		{
			trResult.setInvocableEngine(generateInvocableEngine());
		}
		if(maxwidth < trResult.getWidth())maxwidth = trResult.getWidth();
		if (trResult.getHeight() > 1) {
			for (int i = 1; i < trResult.getHeight() + 1; i++) {
				trArray.add(trResult.getTrResult(i));
			}
		} else{
			trArray.add(trResult);
		}
		
		return this;
	}
	public PageResult append(int trIndex ,  List<TrResult> trResultList) {
		int itr=trIndex;
		for(TrResult trResult : trResultList)
		{
			if(trResult.getTrType() == TrResult.TD_SCRIPT_TYPE)
			{
				trResult.setInvocableEngine(generateInvocableEngine());
			}
			if(maxwidth < trResult.getWidth())maxwidth = trResult.getWidth();
			if (trResult.getHeight() > 1) {
				for (int i = 1; i < trResult.getHeight() + 1; i++) {
					trArray.add(trIndex++,trResult.getTrResult(i));
				}
			} else{
				trArray.add(trIndex++,trResult);
			}
		}
		return this;
	}
	public PageResult append(TableResult trResult) {
		 if(maxwidth < trResult.getWidth())maxwidth = trResult.getWidth();
		trArray.addAll(trResult.getTrAsciiArray());
		return this;
	}
	public PageResult appendHeader(TrResult trResult) {
		if(trResult.getTrType() == TrResult.TD_SCRIPT_TYPE)
		{
			trResult.setInvocableEngine(generateInvocableEngine());
		}
		if (trResult.getHeight() > 1) {
			for (int i = 1; i < trResult.getHeight() + 1; i++) {
				headerArray.add(trResult.getTrResult(i));
			}
		} else
			headerArray.add(trResult);

		return this;
	}
	public PageResult appendFooter(TrResult trResult) {
		if(trResult.getTrType() == TrResult.TD_SCRIPT_TYPE)
		{
			trResult.setInvocableEngine(generateInvocableEngine());
		}
		if (trResult.getHeight() > 1) {
			for (int i = 1; i < trResult.getHeight() + 1; i++) {
				footerArray.add(trResult.getTrResult(i));
			}
		} else
			footerArray.add(trResult);

		return this;
	}
	
	public PageResult append(TrResult trResult,boolean nextPage) {
		if(trResult.getTrType() == TrResult.TD_SCRIPT_TYPE)
		{
			trResult.setInvocableEngine(generateInvocableEngine());
		}
		if (trResult.getHeight() > 1) {
			for (int i = 1; i <= trResult.getHeight() ; i++) {
				if(i==trResult.getHeight())
				{
					TrResult tr = trResult.getTrResult(i);
					if(nextPage)tr.setNextPage(true);
					trArray.add(tr);
				}else trArray.add(trResult.getTrResult(i));
			}
		} else
		{
			if(nextPage) 
			{
				trResult.setNextPage(true);
				trArray.add(trResult);
			}else
			trArray.add(trResult);
		}
		return this;
	}
    private void reCalPage()
    {
    	
    	pageIndex.clear();
    	int lastNext = 0;
    	for(int i=1;i<=trArray.size();i++)
    	{
    		TrResult tr = (TrResult)trArray.get(i-1);
    		if(tr.isNextPage())
    		{
    			pageIndex.add(new Integer(i));
    			lastNext = i;
    		}else
    		{
    			if( i!=0 &&( ((i - lastNext) % this.getDefaultTrNum()) ==0) )
    			{
    				pageIndex.add(new Integer(i));
    			}else
    			{
    				if(i==(trArray.size()))
    				{
    					pageIndex.add(new Integer(i));
    				}
    			}
    		}
    		
    	}
    }
    private boolean indexBoo = false;
    public int getTotalPageNum()
    {
    	if(!indexBoo)
    	{
    		reCalPage();
    	}
    	return pageIndex.size();
    }
    
	protected int getTotalPageNum(boolean indexBoo) {
		this.indexBoo = indexBoo;
		if(indexBoo)
		{
			if(pageIndex.size()==0)
				reCalPage();
		}else
		{
			reCalPage();
		}
		return pageIndex.size();
		
	}

	/*
	 * Page 由第一頁開始
	 */
	public PageResult getPage(int ipage) throws IndexOutOfBoundsException {
		if (ipage == 0)
			throw new IndexOutOfBoundsException("over page");
		int arraySize = trArray.size();
		int totalPageNum = getTotalPageNum(true);
		int endIndex = ((Integer)pageIndex.get(ipage-1)).intValue();
		if(ipage==1){ 
			//System.out.println("START=0::END="+(endIndex));
			return new PageResult(defaultTrNum,
				                               trArray.subList(0, endIndex),headerArray,footerArray);
		}
		else
		{
			int startIndex = ((Integer)pageIndex.get(ipage-2)).intValue();
			return new PageResult(defaultTrNum, 
                    trArray.subList(startIndex, endIndex),headerArray,footerArray);
		}
			
		
	}
    public int getTotalTrNum()
    {
    	return trArray.size() + footerArray.size() + headerArray.size();
    }
    public int getTrSize()
    {
    	return trArray.size();
    }
	public TrResult getTrResult(int itrResult) {
		if (itrResult == 0)
			throw new IndexOutOfBoundsException("over TrResult");
		if (itrResult > trArray.size())
			return null;
		return (TrResult) trArray.get(itrResult - 1);
	}
	public int getFooterTrSize()
	{
		return footerArray.size();
	}
	public TrResult getFooterTrResult(int itrResult) {
		if (itrResult == 0)
			throw new IndexOutOfBoundsException("over TrResult");
		if (itrResult > footerArray.size())
			return null;
		return (TrResult) footerArray.get(itrResult - 1);
	}

	public String toString() {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < headerArray.size(); i++) {
			TrResult td = (TrResult) headerArray.get(i);
			sb.append(td);
			sb.append("\n");//去掉\r
		}
		
		for (int i = 0; i < trArray.size(); i++) {
			TrResult td = (TrResult) trArray.get(i);
			if(td.getWidth()==0 && td.getTrType() == TrResult.TD_SCRIPT_TYPE)
				td.toString();
			else
			{
				sb.append(td);
				sb.append("\n"); //去掉\r
			}
		}
		for (int i = 0; i < footerArray.size(); i++) {
			TrResult td = (TrResult) footerArray.get(i);
			sb.append(td);
			sb.append("\n"); //去掉\r
		}
		return sb.toString();
	}
	

	public static void main(String[] args) {

		PageResult page = new PageResult();

		TableResult table = new TableResult();
		for (int i = 1; i <= 9; i++) {
			TrResult tr = new TrResult();
			TdResult td = new TdResult("AS" + i, 6, TdResult.TD_STYLE_MIDDLE);
			tr.append(td);
			td = new TdResult("BS" + i, 4, TdResult.TD_STYLE_MIDDLE);
			tr.append(td);
			td = new TdResult("CS" + i, 4, TdResult.TD_STYLE_MIDDLE);
			tr.append(td);
			td = new TdResult("CS" + i, 4, TdResult.TD_STYLE_MIDDLE);
			tr.append(td);
			td = new TdResult("CS" + i, 4, TdResult.TD_STYLE_MIDDLE);
			tr.append(td);
			table.append(tr);
		}
		
		{
			TrResult tr = new TrResult();
			TdResult td = new TdResult("AS" , 4, TdResult.TD_STYLE_MIDDLE);
			tr.append(td);
			td = new TdResult("BS" , 6, TdResult.TD_STYLE_MIDDLE);
			tr.append(td);
			td = new TdResult("CS" , 4, TdResult.TD_STYLE_MIDDLE);
			tr.append(td);
			td = new TdResult("CS" , 4, TdResult.TD_STYLE_MIDDLE);
			tr.append(td);
			td = new TdResult("CS" , 4, TdResult.TD_STYLE_MIDDLE);
			tr.append(td);
			table.append(tr);
		}
		{
			TrResult tr = new TrResult();
			TdResult td = new TdResult("AS" , 4, TdResult.TD_STYLE_MIDDLE);
			tr.append(td);
			td = new TdResult("BS" , 6, TdResult.TD_STYLE_MIDDLE);
			tr.append(td);
			td = new TdResult("CS" , 8, TdResult.TD_STYLE_MIDDLE);
			tr.append(td);
			td = new TdResult("CS" , 4, TdResult.TD_STYLE_MIDDLE);
			tr.append(td);
			table.append(tr);
		}
		page.append(table);
		
		for (int i = 1; i <= page.getTotalPageNum(); i++) {
			System.out.println("PAGE=" + i);
			System.out.print(page.getPage(i));
			System.out.println("================");
			
		}
		try {
			FileUtils.writeStringToFile(new File("page.txt"), page.toString(), "BIG5");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}